package xman.mjava.thread;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProduceConsume {
	public static void main(String[] args) {
		QueueContainer container = new QueueContainer();
		Thread produce = new Thread(new Produce(container));
		Thread consume = new Thread(new Consume(container));
		produce.start();
		consume.start();
	}
}

class Produce implements Runnable {
	private QueueContainer container;

	public Produce(QueueContainer container) {
		this.container = container;
	}

	@Override
	public void run() {
		while (true) {
			try {
				container.produce(new QueueEntry());
				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

class Consume implements Runnable {
	private QueueContainer container;

	public Consume(QueueContainer container) {
		this.container = container;
	}

	@Override
	public void run() {
		while (true) {
			container.consume();
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

class QueueContainer {
	private List<QueueEntry> container = new LinkedList<QueueEntry>();
	private final ReentrantLock lock = new ReentrantLock();
	private Condition notFull = lock.newCondition();
	private Condition notEmpty = lock.newCondition();
	private final Integer maxNum = 5;
	private final Integer minNum = 0;

	public void produce(QueueEntry obj) throws Exception {
		try {
			lock.lock();
			while (container.size() >= maxNum) {
				notFull.await();
			}
			container.add(obj);
			notEmpty.signal();
		} finally {
			lock.unlock();
		}
	}

	public void consume() {
		try {
			lock.lock();
			while (container.size() <= minNum) {
				notEmpty.await();
			}
			container.remove(0);
			notFull.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}

class QueueEntry {
}
